<template>
  <layoutHeader></layoutHeader>
  <div>
    <div class="all">
      <video class="video" ref="localCameraVideo" autoplay muted></video>
      <video class="video" ref="remoteCameraVideo" autoplay></video>
      <div v-if="isRoomBusy">工作人员繁忙或不在线，请稍后再试!!!</div>
    </div>
    <div class="buttons">
      <!-- 拨打按钮：仅在未呼叫、未通话且 WebSocket 已连接时显示 -->
      <button
          v-if="!calling && !communicating && isSocketOpen && !isRoomBusy"
          class="button"
          @click="upVideo"
      >
        拨打
      </button>

      <!-- 接听按钮：仅在呼叫中且被呼叫方时显示 -->
      <button
          v-if="calling && called"
          class="button"
          @click="yesVideo"
      >
        接听
      </button>

      <!-- 挂断按钮：在通话中或呼叫中显示 -->
      <button
          v-if="communicating || calling"
          class="button"
          @click="downVideo"
      >
        挂断
      </button>
    </div>
  </div>
  <layoutFooter></layoutFooter>
</template>

<script setup>
import { onMounted, ref } from "vue";

const roomId = ref(null); // 房间号
const localCameraVideo = ref(null); // 本地视频元素
const remoteCameraVideo = ref(null); // 远端视频元素
const called = ref(false); // 是否是接收方
const caller = ref(false); // 是否是发起方
const calling = ref(false); // 呼叫中
const communicating = ref(false); // 视频通话中
const peer = ref(null); // RTCPeerConnection 对象
const localStream = ref(null); // 本地媒体流
const isRoomBusy = ref(false); // 房间是否忙碌
const isSocketOpen = ref(false); // WebSocket 连接状态
const socket = ref(null); // 响应式 WebSocket 引用

// 生成随机用户ID（字符串类型以避免 JSON 解析问题）
const userId = String(Math.floor(Math.random() * 1000000000));

onMounted(() => {
  creatSocket();
});

// 建立 WebSocket 连接
function creatSocket(){
  // 初始化 WebSocket 连接

  socket.value = new WebSocket(`wss://192.168.71.1:8443/websocket/${userId}`);

  // WebSocket 连接打开时的处理
  socket.value.onopen = function(){
    console.log('WebSocket 连接已打开');
    isSocketOpen.value = true; // 设置连接状态为打开
    roomId.value = '0';
    socket.value.send(JSON.stringify({
      type: 'joinRoom',
      roomId: roomId.value
    }));
  };

  // 监听 WebSocket 消息
  socket.value.addEventListener('message', async(message) => {
    const dataJson = JSON.parse(message.data);
    // 处理接收到的消息

    // 用户收到自己被分配的房间号，如果没被分配，则是0,提示工作人员繁忙请稍后再试
    if(dataJson.type === 'getRoomId'){
      console.log(dataJson);
      if(dataJson.roomId === '0') {
        isRoomBusy.value = true;
      } else {
        roomId.value = String(dataJson.roomId);
      }
    }

    // 被呼叫方 接收到 呼叫方 请求通话的消息
    if(dataJson.type === 'callRemote' && !caller.value){ // 不是呼叫方
      console.log('被呼叫方 接收到 呼叫方 请求通话的消息');
      called.value = true;
      calling.value = true;
    }

    // 呼叫方 接收到 被呼叫方 同意通话的消息，发送offer等验证信息
    if(dataJson.type === 'acceptCall' && caller.value){ // 是呼叫方
      console.log('呼叫方 接收到 被呼叫方 同意通话的消息');
      peer.value = new RTCPeerConnection();

      // 添加本地媒体轨道到 RTCPeerConnection
      if (localStream.value) {
        localStream.value.getTracks().forEach(track => {
          peer.value.addTrack(track, localStream.value);
        });
      }

      // 获取 candidate 信息
      peer.value.onicecandidate = (event) => {
        if(event.candidate){
          socket.value.send(JSON.stringify({
            type: 'sendCandidate',
            roomId: roomId.value,
            candidate: event.candidate,
            role: 'caller'
          }));
        }
      };

      // 获取对方的音视频流
      peer.value.ontrack = (event) => {
        if(event.streams && event.streams[0]){
          communicating.value = true;
          calling.value = false;
          remoteCameraVideo.value.srcObject = event.streams[0];
          remoteCameraVideo.value.play();
        }
      };

      // 获取自己的 offer
      const offer = await peer.value.createOffer({
        offerToReceiveAudio: 1,
        offerToReceiveVideo: 1
      });

      // 在本地设置 offer 信息
      await peer.value.setLocalDescription(offer);

      // 发送 offer
      socket.value.send(JSON.stringify({
        type: 'sendOffer',
        roomId: roomId.value,
        offer: offer
      }));
    }

    // 被呼叫方 接收到 呼叫方 发来的 offer，回发 answer 等信息
    if(dataJson.type === 'sendOffer' && !caller.value){ // 不是呼叫方
      console.log('被呼叫方 接收到 呼叫方 发来的 offer');
      peer.value = new RTCPeerConnection();

      // 获取并添加本地媒体流
      try {
        const userMedia = await getUserMedia({ audio: true, video: true });
        localStream.value = userMedia;
        localCameraVideo.value.srcObject = userMedia;
        await localCameraVideo.value.play();

        userMedia.getTracks().forEach(track => {
          peer.value.addTrack(track, userMedia);
        });
      } catch (error) {
        console.error('获取媒体流失败:', error);
        alert('无法获取您的摄像头或麦克风权限。');
        return;
      }

      // 获取对方的音视频流
      peer.value.ontrack = (event) => {
        if(event.streams && event.streams[0]){
          communicating.value = true;
          calling.value = false;
          remoteCameraVideo.value.srcObject = event.streams[0];
          remoteCameraVideo.value.play();
        }
      };

      // 设置远端描述信息
      await peer.value.setRemoteDescription(new RTCSessionDescription(dataJson.offer));

      // 获取 candidate 信息
      peer.value.onicecandidate = (event) => {
        if(event.candidate){
          socket.value.send(JSON.stringify({
            type: 'sendCandidate',
            roomId: roomId.value,
            candidate: event.candidate,
            role: 'called'
          }));
        }
      };

      // 生成 answer
      const answer = await peer.value.createAnswer();

      // 在本地设置 answer 信息
      await peer.value.setLocalDescription(answer);

      // 发送 answer
      socket.value.send(JSON.stringify({
        type: 'sendAnswer',
        roomId: roomId.value,
        answer: answer
      }));
    }

    // 呼叫方 接收到 被呼叫方 发来的 answer 等信息，设置远端描述
    if(dataJson.type === 'sendAnswer' && caller.value){ // 是呼叫方
      console.log('呼叫方 接收到 被呼叫方 发来的 answer');
      await peer.value.setRemoteDescription(new RTCSessionDescription(dataJson.answer));
    }

    // 当双方收到对方发来的 candidate 信息时，调用 addIceCandidate()
    if(dataJson.type === 'sendCandidate'){
      if( (caller.value && dataJson.role === 'called') ||
          (called.value && dataJson.role === 'caller') ){
        console.log('接收到 对方 发来的 candidate');
        try{
          await peer.value.addIceCandidate(new RTCIceCandidate(dataJson.candidate));
        } catch(error){
          console.log("未能设置远端描述", error);
        }
      }
    }

    // 一方收到对方发来的挂断消息
    if(dataJson.type === 'hangUp'){ // 被挂断的
      console.log('接收到 对方 发来的挂断消息');
      handleHangUp();
    }
  });

  // 监听 WebSocket 关闭事件
  socket.value.onclose = function(){
    console.log('WebSocket 连接已关闭');
    isSocketOpen.value = false; // 设置连接状态为关闭
  };

  // 监听 WebSocket 错误事件
  socket.value.onerror = function(error){
    console.error('WebSocket 发生错误:', error);
    alert('WebSocket 连接发生错误，请检查控制台。');
  };
}

// 获取媒体信息
async function getUserMedia(constraints) {
  try {
    if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
      return await navigator.mediaDevices.getUserMedia(constraints);
    } else {
      throw new Error('getUserMedia is not supported in this browser');
    }
  } catch (error) {
    console.error('Error accessing media devices.', error);
    throw error;
  }
}

// 发起视频通话
const upVideo = async () =>{
  if (!socket.value || socket.value.readyState !== WebSocket.OPEN) {
    console.error('WebSocket 尚未连接');
    alert('系统尚未准备好，请稍后再试。');
    return;
  }

  caller.value = true;
  calling.value = true;

  socket.value.send(JSON.stringify({
    type: 'callRemote',
    roomId: roomId.value
  }));

  try {
    const userMedia = await getUserMedia({ audio: true, video: true });
    localStream.value = userMedia;
    localCameraVideo.value.srcObject = userMedia;
    await localCameraVideo.value.play();

    // 将本地媒体流添加到 RTCPeerConnection
    if(peer.value){
      userMedia.getTracks().forEach(track => {
        peer.value.addTrack(track, userMedia);
      });
    }
  } catch (error) {
    console.error('获取媒体流失败:', error);
    alert('无法获取您的摄像头或麦克风权限。');
  }
}

// 接听视频通话
const yesVideo = () =>{
  if (!socket.value || socket.value.readyState !== WebSocket.OPEN) {
    console.error('WebSocket 尚未连接');
    alert('系统尚未准备好，请稍后再试。');
    return;
  }
  socket.value.send(JSON.stringify({
    type: 'acceptCall',
    roomId: roomId.value
  }));
}

// 挂断视频通话
const downVideo = () => {
  caller.value = false;
  called.value = false;
  calling.value = false;
  communicating.value = false;

  if(socket.value && socket.value.readyState === WebSocket.OPEN){
    socket.value.send(JSON.stringify({
      type: 'hangUp',
      roomId: roomId.value,
    }));
  }

  // 关闭 RTCPeerConnection
  if (peer.value) {
    peer.value.close();
    peer.value = null;
  }

  // 停止所有媒体轨道
  if (localStream.value) {
    localStream.value.getTracks().forEach(track => track.stop());
    localStream.value = null;
  }

  // 清理本地视频
  if(localCameraVideo.value && localCameraVideo.value.srcObject){
    localCameraVideo.value.srcObject.getTracks().forEach(track => track.stop());
    localCameraVideo.value.srcObject = null;
  }

  // 清理远端视频
  if(remoteCameraVideo.value && remoteCameraVideo.value.srcObject){
    remoteCameraVideo.value.srcObject.getTracks().forEach(track => track.stop());
    remoteCameraVideo.value.srcObject = null;
  }
}

// 处理挂断逻辑
function handleHangUp(){
  communicating.value = false;
  caller.value = false;
  called.value = false;
  calling.value = false;

  // 关闭 RTCPeerConnection
  if (peer.value) {
    peer.value.close();
    peer.value = null;
  }

  // 停止所有媒体轨道
  if (localStream.value) {
    localStream.value.getTracks().forEach(track => track.stop());
    localStream.value = null;
  }

  // 清理本地视频
  if(localCameraVideo.value && localCameraVideo.value.srcObject){
    localCameraVideo.value.srcObject.getTracks().forEach(track => track.stop());
    localCameraVideo.value.srcObject = null;
  }

  // 清理远端视频
  if(remoteCameraVideo.value && remoteCameraVideo.value.srcObject){
    remoteCameraVideo.value.srcObject.getTracks().forEach(track => track.stop());
    remoteCameraVideo.value.srcObject = null;
  }
}
</script>

<style>
.all{
  width: 360px;
  height: 480px;
  background-color: blue;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.buttons {
  position: absolute;
  top: 600px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 10px;
}

.button {
  padding: 10px 20px;
  background-color: rgb(30, 158, 167);
  color: rgb(255, 255, 255);
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.video {
  width: 360px;
  height: 173px;
  background-color: #4CAF50;
  margin-top: 30px;
  border-radius: 8px;
}
</style>
